package conn

import (
	"gitee.com/cooge/impush/core"
	"gitee.com/cooge/impush/gutil"
	"gitee.com/cooge/impush/message"
	"gitee.com/cooge/impush/stream"
	log "github.com/sirupsen/logrus"
	"net"
	"strings"
	"time"
)

type ClusterConn struct {
	ms               *stream.MessageStream
	callBackMachines CallBackMachines
	delete           DeleteUserHandlerFunc
	add              AddUserHandlerFunc
	nouser           NoUserHandlerFunc
	netbreak         NetBreakHandlerFunc
}

type DeleteUserHandlerFunc func(*ClusterConn, *message.Message)

type AddUserHandlerFunc func(*ClusterConn, *message.Message)

type NetBreakHandlerFunc func(*ClusterConn)

type NoUserHandlerFunc func(string, *ClusterConn)

type CallBackMachines func(*ClusterConn, []string)

func NewClusterConn(conn *net.TCPConn, delete DeleteUserHandlerFunc, add AddUserHandlerFunc, netbreak NetBreakHandlerFunc, nouser NoUserHandlerFunc) *ClusterConn {
	var cs ClusterConn
	cs.delete = delete
	cs.add = add
	cs.netbreak = netbreak
	cs.nouser = nouser
	cs.ms = stream.NewMessageStream(conn)
	return &cs
}

var connList = gutil.NewLinkList()

/**
向所有机器发送信息，在没法知道用户在哪台机器上时使用
*/

func SendMessage(msg *message.Message) {
	msg.Heads[message.TYPE] = message.ALLMESSAGE
	for _, v := range connList.GetAllArray() {
		o, ok := v.(*ClusterConn)
		if ok {
			o.SendMessage(msg)
		}
	}
}

func (this *ClusterConn) SendMessage(msg *message.Message) (int, error) {
	bs := msg.MessageToByte()
	return this.ms.Conn.Write(bs)
}

func (this *ClusterConn) Close(userId string) error {
	core.DeleteUser(userId, this)
	return nil
}

func (this *ClusterConn) close() error {
	core.DeleteValue(this)
	return this.ms.Conn.Close()
}

func (this *ClusterConn) SetReadDeadline() {
	this.ms.Conn.SetReadDeadline(time.Now().Add(time.Duration(30) * time.Minute))
}

func (this *ClusterConn) Start(callBackMachines CallBackMachines) {
	this.callBackMachines = callBackMachines
	go this.start()
}

func (this *ClusterConn) GetUser() string {
	return this.ms.Conn.RemoteAddr().String()
}

func (this *ClusterConn) start() {

	log.Info("集群有新的连接来了", this.GetUser())
	connList.Add(this)

	for {
		mg, err := this.ms.ReadMessage()
		if err != nil {
			log.Info("集群连接断开", err, this.GetUser())
			break
		} else {
			this.handle(mg)
		}
	}
	connList.Delete(this)
	this.close()
	go this.netbreak(this)

}

func (this *ClusterConn) handle(msg *message.Message) {
	ty := msg.Heads.Get(message.TYPE)
	switch ty {
	case message.CLUSTER:
		{
			action := msg.Heads.Get(message.ACTION)
			switch action {
			case message.LIVE:
				{
					bb := string(msg.Body)

					log.Debug("收到机器", bb)

					addess := strings.Split(bb, ";")
					this.callBackMachines(this, addess)
					bs := message.ClusterLive()
					this.ms.Conn.Write(bs)
				}
			case message.SENDCLUSTERUSER:
				{

					this.add(this, msg)

				}
			case message.DELETECLUSTERUSER:
				{

					this.delete(this, msg)
				}
			case message.NOUSER:
				bb := msg.Body
				uids := strings.Split(string(bb), ";")
				for _, k := range uids {
					log.Debug(k, "不存在")
					this.nouser(k, this)
				}
			}
		}
	}
	this.SetReadDeadline()
}
